// 绘制区域
let DrawingArea = {
    init: function (config) {
        let _ = {
            //TODO: halation 光晕 应用到底图被遮挡的方位
            itemList: "grid,image,center,path,line,coord,label,cursor,auxiliary,area,info,btn,msg".split(','),//项目列表-对应属性 imageCanvas...imageContext...
            container: undefined,//容器
            baseMap: undefined,//底图
            position: {
                left: 0,
                top: 0
            },//定位
            coordList: [],//坐标列表（二维数组）
            grabbing: false,
            mode: undefined,//模式（draw 绘制、move 移动）
            isDrawMode: () => _.mode === 'draw',
            asDrawMode: function () {
                // 取消移动模式下所有操作
                _.grabbing = false;
                _.container.style.cursor = 'grab';
                // 重置起源位置
                _.originPosition = undefined;
                // 更新定位
                _.position.left = parseInt(_.imageCanvas.style.left);
                _.position.top = parseInt(_.imageCanvas.style.top);
                // 设置偏移文本
                _.setOffsetText(_.position.left, _.position.top);
                // 设置当前模式为绘制
                this.mode = 'draw';
                this.container.style.cursor = 'default';
                this.setModeText('绘制');
            },
            isMoveMode: () => _.mode === 'move',
            asMoveMode: function () {
                // 取消绘制模式下所有操作
                if (_.status.path.pressing) {
                    _.status.path.pressing = false;
                    _.pathContext.clearRect(0, 0, _.pathCanvas.width, _.pathCanvas.height);
                }
                if (_.status.line.pressing) {
                    _.status.line.pressing = false;
                }
                if (_.status.coord.pressing) {
                    _.status.coord.pressing = false;
                }
                if (_.status.cursor.pressing) {
                    _.status.cursor.pressing = false;
                    _.cursorContext.clearRect(0, 0, _.cursorCanvas.width, _.cursorCanvas.height);
                }
                // 清屏
                _.auxiliaryContext.clearRect(0, 0, _.auxiliaryCanvas.width, _.auxiliaryCanvas.height);
                // 设置当前模式为移动
                this.mode = 'move';
                this.container.style.cursor = 'grab';
                this.setModeText('移动', '#0074e8');
            },
            msgId: undefined,//消息ID
            areaIndex: 0,//区域索引
            latestPosition: undefined,//最新位置（针对绘制）
            originPosition: undefined,//起源位置（针对移动）
            completed: false,//已完成
            gridCanvas: undefined,//网格画布
            imageCanvas: undefined,//图像画布
            centerCanvas: undefined,//中心画布
            pathCanvas: undefined,//路径画布
            lineCanvas: undefined,//线条画布
            coordCanvas: undefined,//坐标画布
            labelCanvas: undefined,//标签画布
            cursorCanvas: undefined,//光标画布
            auxiliaryCanvas: undefined,//辅助画布
            areaCanvas: undefined,//区域画布
            infoCanvas: undefined,//信息画布
            btnCanvas: undefined,//按钮画布
            msgCanvas: undefined,//消息画布
            gridContext: undefined,//网格上下文
            imageContext: undefined,//图像上下文
            centerContext: undefined,//中心上下文
            pathContext: undefined,//路径上下文
            lineContext: undefined,//线条上下文
            coordContext: undefined,//坐标上下文
            labelContext: undefined,//标签上下文
            cursorContext: undefined,//光标上下文
            auxiliaryContext: undefined,//辅助上下文
            areaContext: undefined,//区域上下文
            infoContext: undefined,//信息上下文
            btnContext: undefined,//按钮上下文
            msgContext: undefined,//消息上下文
            getInstance: () => {
                let instance = {
                    container: _.container,
                    moveToCentral: () => _.moveToCentral(),
                    asMoveMode: () => _.asMoveMode(),
                    asDrawMode: () => _.asDrawMode(),
                    enableInfoPanel: () => _.enableInfoPanel(),
                    disableInfoPanel: () => _.disableInfoPanel(),
                    enableGridPanel: () => _.enableGridPanel(),
                    disableGridPanel: () => _.disableGridPanel(),
                    enableCenterPanel: () => _.enableCenterPanel(),
                    disableCenterPanel: () => _.disableCenterPanel(),
                    enableAuxiliaryPanel: () => _.enableAuxiliaryPanel(),
                    disableAuxiliaryPanel: () => _.disableAuxiliaryPanel(),
                    isCompleted: () => _.completed,
                    getCoords: excludeUnfinished => _.getCoords(excludeUnfinished),
                    extract: function () {
                        let canvasList = _.container.querySelectorAll('canvas');
                        log('canvasList', canvasList);
                        let canvasBox = dce('div');
                        canvasBox.id = 'canvasBox';
                        canvasBox.style.width = '400px';
                        canvasBox.style.height = '200px';
                        canvasBox.style.border = '1px solid red';
                        canvasBox.style.position = 'absolute';
                        canvasBox.style.left = '0px';
                        canvasBox.style.top = '0px';
                        canvasBox.style.overflow = 'auto';
                        canvasBox.style.backgroundColor = '#f9f9fa';
                        canvasList.forEach(canvas => {
                            canvas.style.position = '';
                            canvas.style.zIndex = '';
                            canvas.style.left = '';
                            canvas.style.top = '';
                            canvas.style.width = '64px';
                            canvas.style.height = '64px';
                            canvas.style.border = '1px solid green';
                            canvas.style.margin = '4px';
                            canvas.style.backgroundColor = '#0074e8';
                            canvas.textContent = canvas.textContent;
                            canvas.title = canvas.textContent;
                            canvasBox.appendChild(canvas);
                        });
                        document.body.appendChild(canvasBox);
                    },//提取所有canvas，便于在新标签页中打开并保存为图像。
                    help: () => _.help,
                };
                return instance;
            },//获取实例
            config: {
                container: undefined,
                imageUrl: '',
                showInfo: true,
                showGridlines: true,//显示网格线
                showCenterline: true,//显示中心线
                showAuxiliaryLine: true,//显示辅助线
                allowStacking: true,//允许堆叠
                coordList: [],//坐标列表（二维数组）
                maxArea: 1,
                mode: 'draw',
                centerImage: true,
                infoCallback: (t, x, y) => {
                    //action: onmousedown/onmousemove/onmouseup
                },
                whenReady: instance => {
                },
                whenCreateCoord: (areaIndex, x, y) => {
                },
                whenCompleted: () => {
                },
            },//配置
            enableInfoPanel: function () {
                this.infoCanvas.style.opacity = '';
            },//启用信息面板
            disableInfoPanel: function () {
                this.infoCanvas.style.opacity = '0';
            },//禁用信息面板
            enableGridPanel: function () {
                this.gridCanvas.style.opacity = '';
            },//启用网格面板
            disableGridPanel: function () {
                this.gridCanvas.style.opacity = '0';
            },//禁用网格面板
            enableCenterPanel: function () {
                this.centerCanvas.style.opacity = '';
            },//启用中心面板
            disableCenterPanel: function () {
                this.centerCanvas.style.opacity = '0';
            },//禁用中心面板
            enableAuxiliaryPanel: function () {
                this.auxiliaryCanvas.style.opacity = '';
            },//启用辅助面板
            disableAuxiliaryPanel: function () {
                this.auxiliaryCanvas.style.opacity = '0';
            },//禁用辅助面板
            getCoords: function (excludeUnfinished) {
                let coords = [];
                for (let i = 0; i < (excludeUnfinished ? _.areaIndex : _.coordList.length); i++) {
                    coords.push(_.coordList[i]);
                }
                return coords;
            },//获取坐标
            revertColor: function () {
            },//反转颜色
            getPosition: function (event) {
                let x = event.layerX - this.position.left;
                let y = event.layerY - this.position.top;
                x = x < 0 ? 0 : x > this.baseMap.width ? this.baseMap.width : x;
                y = y < 0 ? 0 : y > this.baseMap.height ? this.baseMap.height : y;
                return {x: x, y: y};
            },//获取位置
            buildComponent: function () {
                // 容器引用
                let container = this.container;
                // 支持Tab键导航与keyup事件
                container.tabIndex = 0;
                // 去掉容器轮廓（针对于tabIndex）
                container.style.outline = 'none';
                // 设置样式
                container.style.position = 'relative';
                container.style.overflow = 'hidden';
                // 使容器获得焦点
                container.focus();
                // 获得焦点时
                container.addEventListener('focus', function (event) {
                    _.showMessage('容器获得焦点');
                });
                // 失去焦点时
                container.addEventListener('blur', function (event) {
                    _.showMessage('容器失去焦点', -1);
                });
                // 禁止右键
                container.oncontextmenu = () => false;
                // 禁止选择
                container.onselectstart = () => false;
                // 事件名称列表
                let typeList = 'mouseenter,mouseleave,mouseover,mouseout,mousedown,mousemove,mouseup'.split(',');
                typeList.forEach(type => container.addEventListener(type, _[type]));
                // 键按下
                container.addEventListener('keydown', function (event) {
                    // log('keydown', event.keyCode);//会多次触发
                });
                // 键按？
                container.addEventListener('keypress', function (event) {
                    // log('keypress', event.keyCode);//会多次触发
                });
                // Esc - 取消绘制、取消移动
                container.addEventListener('keyup', function (event) {
                    log('keyup', event.keyCode, event);
                    if (event.keyCode == 27) {//Escape
                        if (_.isMoveMode() && _.grabbing) {
                            _.grabbing = false;
                            _.container.style.cursor = 'grab';
                            // 设置偏移文本
                            _.setOffsetText(_.position.left, _.position.top);
                            // 移动画布
                            _.moveCanvas(_.position.left, _.position.top);
                            // 重置起源位置
                            _.originPosition = undefined;
                        } else if (_.isDrawMode()) {
                            if (_.status.path.pressing) {
                                _.status.path.pressing = false;
                                _.pathContext.clearRect(0, 0, _.pathCanvas.width, _.pathCanvas.height);
                            }
                            if (_.status.line.pressing) {
                                _.status.line.pressing = false;
                            }
                            if (_.status.coord.pressing) {
                                _.status.coord.pressing = false;
                            }
                            if (_.status.cursor.pressing) {
                                _.status.cursor.pressing = false;
                                _.cursorContext.clearRect(0, 0, _.cursorCanvas.width, _.cursorCanvas.height);
                            }
                        }
                    } else if (event.keyCode == 17) {//Control
                        _.hideMessage();
                        if (_.isMoveMode()) {
                            _.asDrawMode();
                        } else if (_.isDrawMode()) {
                            _.asMoveMode();
                        }
                    } else if (event.keyCode == 112) {//F1
                        alert(_.help);
                    }
                });
                // 引用底图
                let baseMap = this.baseMap;
                // 随机堆叠顺序
                let zIndex = Math.floor(Math.random() * 1e4);
                // 初始化属性：画布、上下文
                this.itemList.forEach(item => {
                    let canvas = this[item + 'Canvas'] = dce('canvas');
                    canvas.setAttribute('key', item);
                    canvas.style.position = 'absolute';
                    canvas.style.zIndex = zIndex++;
                    if (item == 'grid' || item == 'info' || item == 'btn' || item == 'msg') {
                        canvas.width = container.clientWidth;
                        canvas.height = container.clientHeight;
                        canvas.style.left = '0px';
                        canvas.style.top = '0px';
                    } else {
                        canvas.width = baseMap.width;
                        canvas.height = baseMap.height;
                        canvas.style.left = this.position.left + 'px';
                        canvas.style.top = this.position.top + 'px';
                    }
                    container.appendChild(canvas);
                    this[item + 'Context'] = canvas.getContext('2d');
                });
                // 居中图像
                if (this.config.centerImage) {
                    this.moveToCentral();
                }
                // 绘制网格线
                if (this.config.showGridlines) {
                    drawGridlines(_.gridCanvas);
                }
                // 绘制图像-底图
                this.imageContext.drawImage(baseMap, 0, 0);
                // 绘制中心线
                if (this.config.showCenterline) {
                    drawCenterline(_.centerCanvas);
                }
                // 设置信息画布内容
                this.setContainerText(container.clientWidth, container.clientHeight);
                this.setBaseMapText(baseMap.width, baseMap.height);
                this.setOffsetText(this.position.left, this.position.top);
                this.setPositionText('?', '?');
                this.setLocationText('?', '?');
                this.setModeText('?');
                this.setAreaText(this.areaIndex + '/' + this.config.maxArea);
                // 设置模式
                if (this.config.mode == 'draw') {
                    this.asDrawMode();
                } else if (this.config.mode == 'move') {
                    this.asMoveMode();
                }
                // 回显坐标
                let coordList = this.config.coordList;
                if (coordList != undefined) {
                    let errorFlag = false;
                    // 检查坐标
                    for (let i = 0; i < coordList.length; i++) {
                        let areaCoords = coordList[i];
                        if (areaCoords.length < 3) {
                            _.showMessage('第 ' + (i + 1) + ' 个区域坐标少于 3 个', -1);
                            errorFlag = true;
                            break;
                        }
                        for (let j = 0; j < areaCoords.length; j++) {
                            let coord = areaCoords[j].split(',');
                            let x = Number(coord[0]);
                            let y = Number(coord[1]);
                            if (x < 0 || x > _.coordCanvas.width || y < 0 || y > _.coordCanvas.height) {
                                _.showMessage('无效的坐标[' + areaCoords[j] + ']', -1);
                                errorFlag = true;
                                break;
                            }
                            for (let k = j + 1; k < areaCoords.length; k++) {
                                if (areaCoords[j] == areaCoords[k]) {
                                    _.showMessage('重复的坐标[' + areaCoords[j] + ']', -1);
                                    errorFlag = true;
                                    break;
                                }
                            }
                            if (errorFlag) {
                                break;
                            }
                        }
                    }
                    if (!errorFlag) {
                        for (let i = 0; i < coordList.length; i++) {
                            let areaCoords = coordList[i];
                            // 绘制区域
                            _.areaContext.beginPath();
                            for (let j = 0; j < areaCoords.length; j++) {
                                let coord = areaCoords[j].split(',');
                                _.coordList[_.areaIndex].push(areaCoords[j]);
                                let x = Number(coord[0]);
                                let y = Number(coord[1]);
                                _.areaContext.lineTo(x, y);
                                // 执行回调函数
                                _.config.whenCreateCoord(_.areaIndex, x, y);
                            }
                            _.areaContext.closePath();
                            _.areaContext.fillStyle = '#00c47a6f';
                            _.areaContext.fill();
                            _.areaIndex++;
                        }
                        // 定义区域文本字体颜色
                        let areaTextColor = undefined;
                        if (_.areaIndex == _.config.maxArea) {
                            // 设置绘制完成标志
                            _.completed = true;
                            // 重置文本
                            _.setPositionText('?', '?');
                            _.setLocationText('?', '?');
                            // 预警颜色
                            areaTextColor = '#e00';
                            // 强制切换为移动模式
                            _.asMoveMode();
                        }
                        // 设置区域文本
                        _.setAreaText(_.areaIndex + '/' + _.config.maxArea, areaTextColor);
                    }
                }
                // 通知调用者已就绪
                this.config.whenReady(this.getInstance());
            },//构建部件
            setContainerText: function (x, y) {
                if (this.config.showInfo) {
                    let text = "容器 " + x + " x " + y;
                    let ctx = this.infoContext;
                    ctx.font = this.INFO_STYLE.font;
                    ctx.clearRect(5, this.INFO_PIXELS[0][0], this.INFO_DIMENSIONS.width, this.INFO_DIMENSIONS.height);
                    ctx.fillStyle = this.INFO_STYLE.backgroundColor;
                    ctx.fillRect(5, this.INFO_PIXELS[0][0], this.INFO_DIMENSIONS.width, this.INFO_DIMENSIONS.height);
                    ctx.fillStyle = this.INFO_STYLE.color;
                    ctx.fillText(text, 8, this.INFO_PIXELS[0][1]);
                }
            },//设置容器文本
            setBaseMapText: function (x, y) {
                if (this.config.showInfo) {
                    let text = "底图 " + x + " x " + y;
                    let ctx = this.infoContext;
                    ctx.font = this.INFO_STYLE.font;
                    ctx.clearRect(5, this.INFO_PIXELS[1][0], this.INFO_DIMENSIONS.width, this.INFO_DIMENSIONS.height);
                    ctx.fillStyle = this.INFO_STYLE.backgroundColor;
                    ctx.fillRect(5, this.INFO_PIXELS[1][0], this.INFO_DIMENSIONS.width, this.INFO_DIMENSIONS.height);
                    ctx.fillStyle = this.INFO_STYLE.color;
                    ctx.fillText(text, 8, this.INFO_PIXELS[1][1]);
                }
            },//设置底图文本
            setOffsetText: function (x, y, color) {
                if (this.config.showInfo) {
                    let text = "偏移 " + x + ", " + y;
                    let ctx = this.infoContext;
                    ctx.font = this.INFO_STYLE.font;
                    ctx.clearRect(5, this.INFO_PIXELS[2][0], this.INFO_DIMENSIONS.width, this.INFO_DIMENSIONS.height);
                    ctx.fillStyle = this.INFO_STYLE.backgroundColor;
                    ctx.fillRect(5, this.INFO_PIXELS[2][0], this.INFO_DIMENSIONS.width, this.INFO_DIMENSIONS.height);
                    ctx.fillStyle = this.INFO_STYLE.color;
                    if (color != undefined) {
                        ctx.fillStyle = color;
                    }
                    ctx.fillText(text, 8, this.INFO_PIXELS[2][1]);
                }
            },//设置偏移文本
            setPositionText: function (x, y) {
                if (this.config.showInfo) {
                    let text = "坐标 " + x + ", " + y;
                    let ctx = this.infoContext;
                    ctx.font = this.INFO_STYLE.font;
                    ctx.clearRect(5, this.INFO_PIXELS[3][0], this.INFO_DIMENSIONS.width, this.INFO_DIMENSIONS.height);
                    ctx.fillStyle = this.INFO_STYLE.backgroundColor;
                    ctx.fillRect(5, this.INFO_PIXELS[3][0], this.INFO_DIMENSIONS.width, this.INFO_DIMENSIONS.height);
                    ctx.fillStyle = this.INFO_STYLE.color;
                    ctx.fillText(text, 8, this.INFO_PIXELS[3][1]);
                }
            },//设置坐标文本
            setLocationText: function (x, y) {
                if (this.config.showInfo) {
                    let text = "位置 " + x + ", " + y;
                    let ctx = this.infoContext;
                    ctx.font = this.INFO_STYLE.font;
                    ctx.clearRect(5, this.INFO_PIXELS[4][0], this.INFO_DIMENSIONS.width, this.INFO_DIMENSIONS.height);
                    ctx.fillStyle = this.INFO_STYLE.backgroundColor;
                    ctx.fillRect(5, this.INFO_PIXELS[4][0], this.INFO_DIMENSIONS.width, this.INFO_DIMENSIONS.height);
                    ctx.fillStyle = this.INFO_STYLE.color;
                    ctx.fillText(text, 8, this.INFO_PIXELS[4][1]);
                }
            },//设置位置文本
            setModeText: function (mode, color) {
                if (this.config.showInfo) {
                    let text = "模式 " + mode;
                    let ctx = this.infoContext;
                    ctx.font = this.INFO_STYLE.font;
                    ctx.clearRect(5, this.INFO_PIXELS[5][0], this.INFO_DIMENSIONS.width, this.INFO_DIMENSIONS.height);
                    ctx.fillStyle = this.INFO_STYLE.backgroundColor;
                    ctx.fillRect(5, this.INFO_PIXELS[5][0], this.INFO_DIMENSIONS.width, this.INFO_DIMENSIONS.height);
                    ctx.fillStyle = this.INFO_STYLE.color;
                    if (color != undefined) {
                        ctx.fillStyle = color;
                    }
                    ctx.fillText(text, 8, this.INFO_PIXELS[5][1]);
                }
            },//设置模式文本
            setAreaText: function (mode, color) {
                if (this.config.showInfo) {
                    let text = "区域 " + mode;
                    let ctx = this.infoContext;
                    ctx.font = this.INFO_STYLE.font;
                    ctx.clearRect(5, this.INFO_PIXELS[6][0], this.INFO_DIMENSIONS.width, this.INFO_DIMENSIONS.height);
                    ctx.fillStyle = this.INFO_STYLE.backgroundColor;
                    ctx.fillRect(5, this.INFO_PIXELS[6][0], this.INFO_DIMENSIONS.width, this.INFO_DIMENSIONS.height);
                    ctx.fillStyle = this.INFO_STYLE.color;
                    if (color != undefined) {
                        ctx.fillStyle = color;
                    }
                    ctx.fillText(text, 8, this.INFO_PIXELS[6][1]);
                }
            },//设置区域文本
            moveToCentral: function () {
                // 获得中心位置
                let position = getCentralPosition(this.container.clientWidth, this.container.clientHeight, this.baseMap.width, this.baseMap.height);
                this.position.left = position.left;
                this.position.top = position.top;
                // 设置偏移文本
                _.setOffsetText(position.left, position.top);
                // 移动画布
                this.moveCanvas(position.left, position.top);
            },//移动到中心
            moveCanvas: function (left, top) {
                // 批量调整定位
                this.itemList.forEach(item => {
                    if (item == 'grid' || item == 'info' || item == 'btn' || item == 'msg') {
                    } else {
                        let canvas = _[item + 'Canvas'];
                        canvas.style.left = left + 'px';
                        canvas.style.top = top + 'px';
                    }
                });
            },//移动画布
            showMessage: function (message, countdown) {
                // 强制清理上一个消息
                clearTimeout(this.msgId);
                // 引用上下文
                let ctx = this.msgContext;
                // 清屏
                ctx.clearRect(0, 0, this.msgCanvas.width, this.msgCanvas.height);
                // 填充背景色
                ctx.fillStyle = '#e00';
                // 设置阴影
                ctx.shadowColor = '#fff';
                ctx.shadowBlur = 48;
                // 填充矩形
                ctx.fillRect(50, this.msgCanvas.height / 2 - 24, this.msgCanvas.width - 100, 48);
                // 创建新的消息
                ctx.fillStyle = '#fff';
                ctx.font = '30px Arial';
                ctx.textAlign = 'center';
                ctx.textBaseline = 'middle';
                ctx.fillText(message, this.msgCanvas.width / 2, this.msgCanvas.height / 2);
                // -1 代表不自动关闭
                if (countdown != -1) {
                    // 更新消息ID
                    this.msgId = setTimeout(() => {
                        this.msgContext.clearRect(0, 0, this.msgCanvas.width, this.msgCanvas.height);
                    }, 666);
                }
            },//显示消息
            hideMessage: function () {
                // 强制清理上一个消息
                clearTimeout(this.msgId);
                // 清屏
                this.msgContext.clearRect(0, 0, this.msgCanvas.width, this.msgCanvas.height);
            },//隐藏消息
            export: function () {
            },//导出
            INFO_STYLE: {
                font: 'bold 18px Arial',
                backgroundColor: '#0074e86f',
                backgroundColor: '#000000',
                color: '#08deaa'
            },//信息画布样式
            INFO_PIXELS: [
                [5, 23],
                [31, 49],
                [57, 75],
                [83, 101],
                [109, 127],
                [135, 153],
                [161, 179]
            ],//信息画布间隔像素+26
            INFO_DIMENSIONS: {
                width: 211,
                height: 23
            },//信息尺寸
            status: {
                grid: {
                    pressing: false
                },
                image: {
                    pressing: false
                },
                center: {
                    pressing: false
                },
                path: {
                    pressing: false
                },
                line: {
                    pressing: false
                },
                coord: {
                    pressing: false
                },
                auxiliary: {
                    pressing: false
                },
                label: {
                    pressing: false
                },
                cursor: {
                    pressing: false
                },
                area: {
                    pressing: false
                },
                info: {
                    pressing: false
                },
                btn: {
                    pressing: false
                },
                msg: {
                    pressing: false
                }
            },//状态
            handler: {
                grid: {
                    mouseenter: event => {
                    },
                    mouseleave: event => {
                    },
                    mouseover: event => {
                    },
                    mouseout: event => {
                    },
                    mousedown: event => {
                    },
                    mousemove: event => {
                    },
                    mouseup: event => {
                    }
                },
                image: {
                    mouseenter: event => {
                    },
                    mouseleave: event => {
                        // 设置坐标文本
                        _.setLocationText('?', '?');
                    },
                    mouseover: event => {
                    },
                    mouseout: event => {
                    },
                    mousedown: event => {
                    },
                    mousemove: event => {
                        // 获取位置
                        let position = _.getPosition(event);
                        let x = position.x;
                        let y = position.y;
                        // 设置坐标文本
                        _.setLocationText(x, y);
                    },
                    mouseup: event => {
                    }
                },
                center: {
                    mouseenter: event => {
                    },
                    mouseleave: event => {
                    },
                    mouseover: event => {
                    },
                    mouseout: event => {
                    },
                    mousedown: event => {
                    },
                    mousemove: event => {
                    },
                    mouseup: event => {
                    }
                },
                path: {
                    mouseenter: event => {
                    },
                    mouseleave: event => {
                        if (_.status.path.pressing) {
                            _.status.path.pressing = false;
                            _.pathContext.clearRect(0, 0, _.pathCanvas.width, _.pathCanvas.height);
                        }
                    },
                    mouseover: event => {
                    },
                    mouseout: event => {
                    },
                    mousedown: event => {
                        if (mouseLeft(event)) {
                            if (_.latestPosition != undefined) {
                                if (!_.status.path.pressing) {
                                    _.status.path.pressing = true;
                                    // 获取位置
                                    let position = _.getPosition(event);
                                    let x = position.x;
                                    let y = position.y;
                                    // 绘制路径
                                    _.pathContext.strokeStyle = '#00c47a';
                                    _.pathContext.lineWidth = 4;
                                    _.pathContext.lineCap = 'round';
                                    _.pathContext.lineJoin = 'round';
                                    _.pathContext.beginPath();
                                    _.pathContext.moveTo(_.latestPosition.x, _.latestPosition.y);
                                    _.pathContext.lineTo(x, y);
                                    _.pathContext.closePath();
                                    _.pathContext.stroke();
                                }
                            }
                        }
                    },
                    mousemove: event => {
                        if (_.status.path.pressing) {
                            _.pathContext.clearRect(0, 0, _.pathCanvas.width, _.pathCanvas.height);
                            // 获取位置
                            let position = _.getPosition(event);
                            let x = position.x;
                            let y = position.y;
                            // 绘制路径
                            _.pathContext.strokeStyle = '#00c47a';
                            _.pathContext.lineWidth = 4;
                            _.pathContext.lineCap = 'round';
                            _.pathContext.lineJoin = 'round';
                            _.pathContext.beginPath();
                            _.pathContext.moveTo(_.latestPosition.x, _.latestPosition.y);
                            _.pathContext.lineTo(x, y);
                            _.pathContext.closePath();
                            _.pathContext.stroke();
                        }
                    },
                    mouseup: event => {
                        if (mouseLeft(event)) {
                            if (_.status.path.pressing) {
                                _.status.path.pressing = false;
                                _.pathContext.clearRect(0, 0, _.pathCanvas.width, _.pathCanvas.height);
                            }
                        }
                    }
                },
                line: {
                    mouseenter: event => {
                    },
                    mouseleave: event => {
                        if (_.status.line.pressing) {
                            _.status.line.pressing = false;
                        }
                    },
                    mouseover: event => {
                    },
                    mouseout: event => {
                    },
                    mousedown: event => {
                        if (mouseLeft(event)) {
                            if (_.latestPosition != undefined) {
                                if (!_.status.line.pressing) {
                                    _.status.line.pressing = true;
                                }
                            }
                        }
                    },
                    mousemove: event => {
                    },
                    mouseup: event => {
                        if (mouseLeft(event)) {
                            if (_.status.line.pressing) {
                                _.status.line.pressing = false;
                                // 获取位置
                                let position = _.getPosition(event);
                                let x = position.x;
                                let y = position.y;
                                // 如果坐标集合中不存在新坐标，则绘制直线
                                //向坐标集合中添加元素
                                let coord = x + ',' + y;//坐标
                                let exist = false;
                                let index = 0;
                                for (let i = 0; i < _.coordList[_.areaIndex].length; i++) {
                                    if (coord == _.coordList[_.areaIndex][i]) {
                                        exist = true;
                                        index = i;
                                        break;
                                    }
                                }
                                if (!exist) {
                                    // 绘制路径
                                    _.lineContext.strokeStyle = '#00c47a';
                                    _.lineContext.lineWidth = 4;
                                    _.lineContext.lineCap = 'round';
                                    _.lineContext.lineJoin = 'round';
                                    _.lineContext.beginPath();
                                    _.lineContext.moveTo(_.latestPosition.x, _.latestPosition.y);
                                    _.lineContext.lineTo(x, y);
                                    _.lineContext.closePath();
                                    _.lineContext.stroke();
                                }
                            }
                        }
                    }
                },
                coord: {
                    mouseenter: event => {
                    },
                    mouseleave: event => {
                        if (_.status.coord.pressing) {
                            _.status.coord.pressing = false;
                            _.showMessage('鼠标移出容器了');
                        }
                    },
                    mouseover: event => {
                    },
                    mouseout: event => {
                    },
                    mousedown: event => {
                        if (mouseLeft(event)) {
                            if (!_.status.coord.pressing) {
                                _.status.coord.pressing = true;
                                _.hideMessage();
                            }
                        }
                    },
                    mousemove: event => {
                    },
                    mouseup: event => {
                        if (mouseLeft(event)) {
                            if (_.status.coord.pressing) {
                                _.status.coord.pressing = false;
                                // 获取位置
                                let position = _.getPosition(event);
                                let x = position.x;
                                let y = position.y;
                                //向坐标集合中添加元素
                                let coord = x + ',' + y;//坐标
                                let exist = false;
                                let index = 0;
                                for (let i = 0; i < _.coordList[_.areaIndex].length; i++) {
                                    if (coord == _.coordList[_.areaIndex][i]) {
                                        exist = true;
                                        index = i;
                                        break;
                                    }
                                }
                                if (exist) {
                                    _.showMessage('坐标[' + coord + ']已存在，索引 ' + index);
                                } else {
                                    _.coordList[_.areaIndex].push(coord);
                                    //绘制坐标
                                    _.coordContext.beginPath();
                                    _.coordContext.arc(x, y, 4, 0, 2 * Math.PI);
                                    _.coordContext.closePath();
                                    _.coordContext.lineWidth = 4;
                                    _.coordContext.strokeStyle = '#ffffff';
                                    _.coordContext.stroke();
                                    _.coordContext.fillStyle = '#3c8aff';
                                    _.coordContext.fill();
                                    _.setPositionText(x, y);
                                    _.latestPosition = {x: x, y: y};
                                    // 执行回调函数
                                    _.config.whenCreateCoord(_.areaIndex, x, y);
                                }
                            }
                        }
                    }
                },
                label: {
                    mouseenter: event => {
                    },
                    mouseleave: event => {
                    },
                    mouseover: event => {
                    },
                    mouseout: event => {
                    },
                    mousedown: event => {
                    },
                    mousemove: event => {
                    },
                    mouseup: event => {
                    }
                },
                cursor: {
                    mouseenter: event => {
                    },
                    mouseleave: event => {
                        if (_.status.cursor.pressing) {
                            _.status.cursor.pressing = false;
                            _.cursorContext.clearRect(0, 0, _.cursorCanvas.width, _.cursorCanvas.height);
                        }
                    },
                    mouseover: event => {
                    },
                    mouseout: event => {
                    },
                    mousedown: event => {
                        if (mouseLeft(event)) {
                            if (!_.status.cursor.pressing) {
                                _.status.cursor.pressing = true;
                                // 获取位置
                                let position = _.getPosition(event);
                                let x = position.x;
                                let y = position.y;
                                // 绘制圆形光标
                                _.cursorContext.beginPath();
                                _.cursorContext.arc(x, y, 4, 0, 2 * Math.PI);
                                _.cursorContext.closePath();
                                _.cursorContext.lineWidth = 4;
                                _.cursorContext.strokeStyle = '#ffffff';
                                _.cursorContext.stroke();
                                _.cursorContext.fillStyle = '#3c8aff';
                                _.cursorContext.fill();
                            }
                        }
                    },
                    mousemove: event => {
                        if (_.status.cursor.pressing) {
                            _.cursorContext.clearRect(0, 0, _.cursorCanvas.width, _.cursorCanvas.height);
                            // 获取位置
                            let position = _.getPosition(event);
                            let x = position.x;
                            let y = position.y;
                            // 绘制圆形光标
                            _.cursorContext.beginPath();
                            _.cursorContext.arc(x, y, 4, 0, 2 * Math.PI);
                            _.cursorContext.closePath();
                            _.cursorContext.lineWidth = 4;
                            _.cursorContext.strokeStyle = '#ffffff';
                            _.cursorContext.stroke();
                            _.cursorContext.fillStyle = '#3c8aff';
                            _.cursorContext.fill();
                        }
                    },
                    mouseup: event => {
                        if (mouseLeft(event)) {
                            if (_.status.cursor.pressing) {
                                _.status.cursor.pressing = false;
                                _.cursorContext.clearRect(0, 0, _.cursorCanvas.width, _.cursorCanvas.height);
                            }
                        }
                    }
                },
                auxiliary: {
                    mouseenter: event => {
                    },
                    mouseleave: event => {
                        _.auxiliaryContext.clearRect(0, 0, _.auxiliaryCanvas.width, _.auxiliaryCanvas.height);
                    },
                    mouseover: event => {
                    },
                    mouseout: event => {
                    },
                    mousedown: event => {
                    },
                    mousemove: event => {
                        // 获取位置
                        let position = _.getPosition(event);
                        let x = position.x;
                        let y = position.y;
                        // 引用上下文
                        let ctx = _.auxiliaryContext;
                        // 清屏
                        ctx.clearRect(0, 0, _.auxiliaryCanvas.width, _.auxiliaryCanvas.height);
                        // 填充样式
                        ctx.fillStyle = '#fff699';
                        ctx.fillStyle = '#fff';
                        // 填充横轴
                        ctx.fillRect(0, y, _.auxiliaryCanvas.width, 1);
                        // 绘制纵轴
                        ctx.fillRect(x, 0, 1, _.auxiliaryCanvas.height);
                    },
                    mouseup: event => {
                    }
                },
                area: {
                    mouseenter: event => {
                    },
                    mouseleave: event => {
                    },
                    mouseover: event => {
                    },
                    mouseout: event => {
                    },
                    mousedown: event => {
                    },
                    mousemove: event => {
                    },
                    mouseup: event => {
                        if (event.buttons == 0 && mouseRight(event)) {
                            if (_.coordList[_.areaIndex].length < 3) {
                                _.showMessage('至少需要3个坐标才能闭合');
                            } else {
                                // 清除画布
                                _.coordContext.clearRect(0, 0, _.coordCanvas.width, _.coordCanvas.height);
                                _.lineContext.clearRect(0, 0, _.lineCanvas.width, _.lineCanvas.height);
                                // 绘制区域
                                _.areaContext.beginPath();
                                for (let i = 0; i < _.coordList[_.areaIndex].length; i++) {
                                    let coord = _.coordList[_.areaIndex][i].split(',');
                                    let x = Number(coord[0]);
                                    let y = Number(coord[1]);
                                    _.areaContext.lineTo(x, y);
                                }
                                _.areaContext.closePath();
                                _.areaContext.fillStyle = '#00c47a6f';
                                _.areaContext.fill();
                                // 重置最新位置
                                _.latestPosition = undefined;
                                // 定义区域文本字体颜色
                                let areaTextColor = undefined;
                                // 区域索引自增
                                _.areaIndex++;
                                // 检查区域索引
                                if (_.areaIndex == _.config.maxArea) {
                                    // 设置绘制完成标志
                                    _.completed = true;
                                    // 重置文本
                                    _.setPositionText('?', '?');
                                    _.setLocationText('?', '?');
                                    // 预警颜色
                                    areaTextColor = '#e00';
                                    // 清除画布
                                    _.auxiliaryContext.clearRect(0, 0, _.auxiliaryCanvas.width, _.auxiliaryCanvas.height);
                                    // 执行回调函数
                                    _.config.whenCompleted();
                                }
                                // 设置区域文本
                                _.setAreaText(_.areaIndex + '/' + _.config.maxArea, areaTextColor);
                            }
                        }
                    }
                },
                info: {
                    mouseenter: event => {
                    },
                    mouseleave: event => {
                    },
                    mouseover: event => {
                    },
                    mouseout: event => {
                    },
                    mousedown: event => {
                    },
                    mousemove: event => {
                    },
                    mouseup: event => {
                    }
                },
                btn: {
                    mouseenter: event => {
                    },
                    mouseleave: event => {
                    },
                    mouseover: event => {
                    },
                    mouseout: event => {
                    },
                    mousedown: event => {
                    },
                    mousemove: event => {
                    },
                    mouseup: event => {
                    }
                },
                msg: {
                    mouseenter: event => {
                    },
                    mouseleave: event => {
                    },
                    mouseover: event => {
                    },
                    mouseout: event => {
                    },
                    mousedown: event => {
                    },
                    mousemove: event => {
                    },
                    mouseup: event => {
                    }
                }
            },//处理器
            mouseenter: function (event) {
                _.container.focus();
                if (!_.completed && _.isDrawMode()) {
                    _.itemList.forEach(item => _.handler[item].mouseenter(event));
                }
            },
            mouseleave: function (event) {
                if (!_.completed && _.isDrawMode()) {
                    _.itemList.forEach(item => _.handler[item].mouseleave(event));
                } else if (_.isMoveMode() && mouseLeft(event) && _.grabbing) {
                    _.grabbing = false;
                    _.container.style.cursor = 'grab';
                    // 重置起源位置
                    _.originPosition = undefined;
                    // 更新定位
                    _.position.left = parseInt(_.imageCanvas.style.left);
                    _.position.top = parseInt(_.imageCanvas.style.top);
                    // 设置偏移文本
                    _.setOffsetText(_.position.left, _.position.top);
                    _.showMessage('鼠标移出容器了');
                }
            },
            mouseover: function (event) {
                if (!_.completed && _.isDrawMode()) {
                    _.itemList.forEach(item => _.handler[item].mouseover(event));
                }
            },
            mouseout: function (event) {
                if (!_.completed && _.isDrawMode()) {
                    _.itemList.forEach(item => _.handler[item].mouseout(event));
                }
            },
            mousedown: function (event) {
                if (!_.completed && _.isDrawMode()) {
                    _.itemList.forEach(item => _.handler[item].mousedown(event));
                } else if (_.isMoveMode() && mouseLeft(event) && !_.grabbing) {
                    _.grabbing = true;
                    _.container.style.cursor = 'grabbing';
                    _.originPosition = {x: event.layerX, y: event.layerY};
                    _.hideMessage();
                } else if (_.completed && _.isDrawMode()) {
                    _.showMessage('区域已达上限');
                }
            },
            mousemove: function (event) {
                if (!_.completed && _.isDrawMode()) {
                    _.itemList.forEach(item => _.handler[item].mousemove(event));
                } else if (_.isMoveMode() && mouseLeft(event) && _.grabbing) {
                    // 计算移动距离
                    let distance = {x: event.layerX - _.originPosition.x, y: event.layerY - _.originPosition.y};
                    let left = _.position.left + distance.x;
                    let top = _.position.top + distance.y;
                    // 设置偏移文本
                    _.setOffsetText(left, top, '#0074e8');
                    // 移动画布
                    _.moveCanvas(left, top);
                }
            },
            mouseup: function (event) {
                if (!_.completed && _.isDrawMode()) {
                    _.itemList.forEach(item => _.handler[item].mouseup(event));
                } else if (_.isMoveMode() && mouseLeft(event) && _.grabbing) {
                    _.grabbing = false;
                    _.container.style.cursor = 'grab';
                    // 重置起源位置
                    _.originPosition = undefined;
                    // 更新定位
                    _.position.left = parseInt(_.imageCanvas.style.left);
                    _.position.top = parseInt(_.imageCanvas.style.top);
                    // 设置偏移文本
                    _.setOffsetText(_.position.left, _.position.top);
                } else if (_.isMoveMode() && mouseRight(event) && !_.grabbing) {
                    _.asDrawMode();
                }
            },
            help: `
说明：
    １. 左上方显示的信息：
    容器，表示容器的宽度和高度，以像素计；
    底图，表示底图的宽度和高度，以像素计；
    偏移，表示底图左上角相对于容器左上角的距离，以像素计；
    坐标，表示最后一个坐标相对于底图左上角的距离，以像素计；
    位置，表示鼠标指针相对于底图左上角的距离，以像素计；
    模式，表示容器的当前模式（移动、绘制）；
    区域，表示区域统计情况（当前数量/最大数量）；
    ２. 按Ctrl键切换模式（注意：需确保容器已获得焦点）。
    ３. 当容器失去焦点时，可将鼠标移至容器上方，再点击鼠标中键（滚轮），使其再次获得焦点。
    ４. 在移动、绘制过程中，按Esc键可取消当前操作。
    ５. 在绘制模式下，按下鼠标左键后，会出现圆形坐标，期间可自由移动，直至松开鼠标左键。
    再次按下鼠标左键后，会出现一条直线，期间可自由移动，直至松开鼠标左键。
    当达到3个坐标时，点击鼠标右键后，将以这些坐标在底图上绘制一片区域。
    当鼠标移出容器后，将自动取消当前操作。
    当鼠标移出底图，未移出容器时，允许继续操作，但坐标会被限制在底图内。
    ６. 在移动模式下，点击鼠标右键后，将切换为绘制模式。
    `,//
            xxx: undefined,//
        };
        // 初始化容器
        let container = config.container;
        if (container == null) {
            throw 'invalid container';
        }
        _.container = container;
        _.config.container = config.container;
        // 初始化回调函数
        if (isFunction(config.whenReady)) {
            _.config.whenReady = config.whenReady;
        }
        if (isFunction(config.whenCreateCoord)) {
            _.config.whenCreateCoord = config.whenCreateCoord;
        }
        if (isFunction(config.whenCompleted)) {
            _.config.whenCompleted = config.whenCompleted;
        }
        // 初始化信息显示开关
        if (config.showInfo != undefined) {
            _.config.showInfo = config.showInfo;
        }
        // 初始化居中图像
        if (config.centerImage != undefined) {
            _.config.centerImage = config.centerImage;
        }
        // 初始化允许堆叠
        if (config.allowStacking != undefined) {
            _.config.allowStacking = config.allowStacking;
        }
        // 初始化显示网格线
        if (config.showGridlines != undefined) {
            _.config.showGridlines = config.showGridlines;
        }
        // 初始化显示中心线
        if (config.showCenterline != undefined) {
            _.config.showCenterline = config.showCenterline;
        }
        // 初始化显示辅助线
        if (config.showAuxiliaryLine != undefined) {
            _.config.showAuxiliaryLine = config.showAuxiliaryLine;
        }
        // 初始化最大区域个数
        if (config.maxArea != undefined) {
            _.config.maxArea = config.maxArea;
        }
        // 初始化模式
        if (config.mode != undefined) {
            _.config.mode = config.mode;
        }
        // 初始化坐标列表
        _.coordList = [];
        for (let i = 0; i < _.config.maxArea; i++) {
            _.coordList.push([]);
        }
        // 初始化默认坐标
        if (config.coordList != undefined) {
            _.config.coordList = config.coordList;
        }
        // 初始化底图
        let baseMap = new Image();
        baseMap.src = config.imageUrl;
        baseMap.onload = () => {
            _.baseMap = baseMap;
            _.config.imageUrl = config.imageUrl;
            // 构建部件
            _.buildComponent();
        };
        baseMap.onerror = () => {
            throw '无效的 imageUrl';
        };
    }
};